import { BadRequest, NotFound } from 'http-errors'
import { Attributes, InferCreationAttributes, Op } from 'sequelize'
import Category from '@/database/models/category'
import Attribute from '@/database/models/attribute'
import AttributeValue from '@/database/models/attributevalue'
import sequelize from '@/database/models'

const getAttributes = async (query: Query) => {
  if (!query.categoryId) {
    throw new BadRequest('分类ID不能为空。')
  }
  const pageNum = Math.abs(Number(query.pageNum)) || 1
  const pageSize = Math.abs(Number(query.pageSize)) || 10
  const offset = (pageNum - 1) * pageSize
  const category = await Category.findByPk(+query.categoryId)
  if (!category) {
    throw new NotFound(`ID:${+query.categoryId}的分类未找到。`)
  }
  const attributes = await category.getAttributes({
    order: [['id', 'DESC']],
    attributes: { exclude: ['CategoryId'] },
    limit: pageSize,
    offset,
    include: {
      model: AttributeValue,
      as: 'values',
      through: {
        attributes: [],
      },
    },
  })
  const count = await category.countAttributes()
  return {
    attributes,
    pagination: {
      total: count,
      pageNum,
      pageSize,
    },
  }
}

const getAttributeInfo = async (id: number) => {
  const attribute = await getAttribute(id)
  return attribute
}

type ValType = Attributes<AttributeValue>

const addAttributeAndValues = async (body: Body) => {
  const t = await sequelize.transaction()
  try {
    const { categoryId, name, values } = body
    if (!categoryId) {
      throw new BadRequest('分类ID不能为空。')
    }
    const category = await Category.findByPk(+categoryId)
    if (!category) {
      throw new NotFound(`ID:${categoryId}的分类未找到。`)
    }
    const attribute = await category.createAttribute(
      {
        name,
      },
      { transaction: t },
    )
    if (!values) {
      await t.commit()
      return attribute
    }
    if (!Array.isArray(values)) {
      throw new BadRequest('属性值必须是数组,eg: [{id?:number,value:string}]。')
    }
    const noIdValues = (values as ValType[]).filter((d) => !d.id)
    const ids = (values as ValType[]).filter((d) => d.id).map((d) => d.id)
    const hasIdValues = await AttributeValue.findAll({
      where: {
        id: {
          [Op.in]: ids,
        },
      },
    })
    const attributeValues = await AttributeValue.bulkCreate(noIdValues, {
      transaction: t,
      validate: true,
    })
    const resAttributeValues = await attribute.addAttributes([...attributeValues, ...hasIdValues], {
      transaction: t,
    })
    await t.commit()
    return resAttributeValues
  } catch (error) {
    await t.rollback()
    throw error
  }
}

/**
 * 公共方法：查询当前属性
 */
async function getAttribute(id: number) {
  const attribute = await Attribute.findByPk(id, {
    attributes: { exclude: ['CategoryId'] },
  })
  if (!attribute) {
    throw new NotFound(`ID:${id}的属性未找到。`)
  }
  return attribute
}

export default {
  getAttributes,
  getAttributeInfo,
  addAttributeAndValues,
}
